using System;
using System.Text;
using Com.ContentRendering.Api.ParserEngine.Exceptions;

namespace Com.ContentRendering.Api.ParserEngine.State
{
    /// <summary/>
    internal abstract class AbstractNameState : AbstractState
    {
        protected StringBuilder _stringBuilder;

        /// <summary/>
        internal AbstractNameState(AbstractState state) : base(state) 
        {
            this._stringBuilder = new StringBuilder();
        }

        /// <summary/>
        protected abstract void AddOutputTag();

        /// <summary/>
        protected abstract OutputNodeInterface AddSubstitutionTag();

        /// <summary/>
        protected abstract OutputNodeInterface AddTransparentTag();
        
        /// <summary/>
        protected abstract OutputNodeInterface AddIfTag();

        /// <summary/>
        protected abstract OutputNodeInterface AddIfNotTag();

        /// <summary/>
        protected sealed override void ParseEscapeCharacter()
        {
            throw new TagNameInvalidException();
        }

        /// <summary/>
        protected sealed override void ParseStartCharacter()
        {
            throw new TagNameInvalidException();
        }
        
        /// <summary/>
        protected sealed override void ParseEndCharacter()
        {
            // has nothing been written to the parameter name
            if (this._stringBuilder.Length == 0)
            {
                throw new TagNameEmptyException();
            }

            // append the output tag from the concrete class
            this.AddOutputTag();

            // the state needs to be updated
            base._documentParser.State = new ContentState(this);
        }

        /// <summary/>
        protected sealed override void ParseSubstitutionCharacter()
        {
            // if anything was written to the name then the exclamation is part of the name and thats invalid
            if (this._stringBuilder.Length == 0)
            {
                throw new TagNameEmptyException();
            }

            // append the output tag from the concrete class
            base._outputNode = this.AddSubstitutionTag();

            // the state needs to be updated
            base._documentParser.State = new ContentState(this);
        }

        /// <summary/>
        protected sealed override void ParseTransparentCharacter()
        {
            // if anything was written to the name then the exclamation is part of the name and thats invalid
            if (this._stringBuilder.Length == 0)
            {
                throw new TagNameEmptyException();
            }

            // append the output tag from the concrete class
            base._outputNode = this.AddTransparentTag();

            // the state needs to be updated
            base._documentParser.State = new ContentState(this);
        }

        /// <summary/>
        protected sealed override void ParseIfCharacter()
        {
            // if anything was written to the name then the exclamation is part of the name and thats invalid
            if (this._stringBuilder.Length == 0)
            {
                throw new TagNameEmptyException();
            }

            // append the output tag from the concrete class
            base._outputNode = this.AddIfTag();

            // the state needs to be updated
            base._documentParser.State = new ContentState(this);
        }

        /// <summary/>
        protected sealed override void ParseIfNotCharacter()
        {
            // if anything was written to the name then the exclamation is part of the name and thats invalid
            if (this._stringBuilder.Length == 0)
            {
                throw new TagNameEmptyException();
            }
            
            // append the output tag from the concrete class
            base._outputNode = this.AddIfNotTag();

            // the state needs to be updated
            base._documentParser.State = new ContentState(this);
        }

        /// <summary/>
        protected sealed override void ParseOtherCharacter(char value)
        {
            // fail if the attribute name contains invalid characters
            if (!char.IsLetter(value))
            {
                throw new TagNameInvalidException();
            }

            this._stringBuilder.Append(value);
        }

        /// <summary/>
        protected sealed override void EndHandler()
        {
            throw new MissingEndCharacterException();
        }
    }
}
